"""
D5Common 模块提供 D5Core 的公共工具和数据结构。

此模块包含各种基础数据类型、向量实现、颜色处理以及单例装饰器等核心功能。
"""
from enum import Enum
from functools import wraps
import threading

__D5Instances = {}
__D5Lock = threading.Lock()

def D5Singleton(cls):
    """
    单例装饰器，确保被装饰的类只有一个实例。
    
    当多次实例化同一个类时，将返回相同的实例。使用类的完全限定名称作为键，
    确保不同模块中同名的类能够正确区分。
    
    :param cls: 要装饰的类
    :type cls: type
    :return: 返回一个包装函数，该函数确保只创建一个类实例
    :rtype: function
    
    :example:
    
    >>> @D5Singleton
    >>> class MyClass:
    >>>     pass
    >>>
    >>> a = MyClass()
    >>> b = MyClass()
    >>> a is b  # 返回 True
    """
    @wraps(cls)
    def wrapper(*args, **kwargs):
        # 使用完全限定名称作为键，包括模块名
        cls_key = cls.__module__ + '.' + cls.__name__
        canonical_cls = getattr(cls, '__canonical_cls__', cls)
        
        if cls_key not in __D5Instances:
            with __D5Lock:
                # Double-checked locking pattern
                if cls_key not in __D5Instances:
                    instance = canonical_cls(*args, **kwargs)
                    __D5Instances[cls_key] = instance
        return __D5Instances[cls_key]
    
    # 保持原始类引用
    wrapper.__canonical_cls__ = cls
    return wrapper

class Rotator:
    """
    欧拉角旋转类，表示三维空间中的旋转（以度为单位）。
    """
    def __init__(self, roll: float, pitch: float, yaw: float):
        self.pitch = pitch
        self.yaw = yaw
        self.roll = roll

    @staticmethod
    def from_str(s: str):
        """
        从字符串创建 Rotator 对象。
        :param s: 格式为 "pitch,yaw,roll" 的字符串
        :type s: str
        :return: 新的 Rotator 对象
        :rtype: Rotator

        :example:
        >>> Rotator.from_str("10,20,30")
        Rotator(10.0, 20.0, 30.0)
        """
        parts = s.split(",")
        pitch, yaw, roll = map(float, parts[:3])
        return Rotator(pitch, yaw, roll)

    def to_str(self) -> str:
        """
        返回旋转的字符串表示，格式为 "pitch,yaw,roll"
        :return: 字符串
        :rtype: str
        """
        return f"{self.pitch},{self.yaw},{self.roll}"

    def __str__(self):
        return f"({self.pitch},{self.yaw},{self.roll})"




class Vector2:
    """
    二维向量类，表示二维空间中的点或向量。
    
    提供基本的二维坐标表示和字符串转换功能。
    
    :ivar x: X 坐标
    :vartype x: float
    :ivar y: Y 坐标
    :vartype y: float
    """
    
    @staticmethod
    def from_str(s):
        """
        从字符串创建 Vector2 对象。
        
        :param s: 格式为 "x,y" 的字符串
        :type s: str
        :return: 新的 Vector2 对象
        :rtype: Vector2
        
        :example:
        
        >>> Vector2.from_str("1.0,2.0")
        (1.0,2.0)
        """
        x, y = map(float, s.split(","))
        return Vector2(x, y)

    def __init__(self, x, y):
        """
        初始化 Vector2 实例。
        
        :param x: X 坐标
        :type x: float
        :param y: Y 坐标
        :type y: float
        """
        self.x = x
        self.y = y
    
    def __str__(self):
        """
        返回向量的字符串表示。
        
        :return: 形如 "(x,y)" 的字符串
        :rtype: str
        """
        return f"({self.x},{self.y})"
    
    def to_str(self):
        """
        将向量转换为字符串格式。
        
        :return: 形如 "x,y" 的字符串
        :rtype: str
        """
        return f"{self.x},{self.y}"


class Vector3(Vector2):
    """
    三维向量类，表示三维空间中的点或向量。
    
    继承自 Vector2 类，增加了 z 坐标。
    
    :ivar x: X 坐标
    :vartype x: float
    :ivar y: Y 坐标
    :vartype y: float
    :ivar z: Z 坐标
    :vartype z: float
    """
    
    @staticmethod
    def from_str(s):
        """
        从字符串创建 Vector3 对象。
        
        :param s: 格式为 "x,y,z" 的字符串
        :type s: str
        :return: 新的 Vector3 对象
        :rtype: Vector3
        
        :example:
        
        >>> Vector3.from_str("1.0,2.0,3.0")
        (1.0,2.0,3.0)
        """
        parts = s.split(",")
        # Take only the first 3 components, ignoring any additional ones
        x, y, z = map(float, parts[:3])
        return Vector3(x, y, z)
    
    def __init__(self, x, y, z):
        """
        初始化 Vector3 实例。
        
        :param x: X 坐标
        :type x: float
        :param y: Y 坐标
        :type y: float
        :param z: Z 坐标
        :type z: float
        """
        super().__init__(x, y)
        self.z = z
    
    def __add__(self, other):
        """
        实现向量加法。
        
        :param other: 另一个 Vector3 对象
        :type other: Vector3
        :return: 新的 Vector3 对象，表示两个向量的和
        :rtype: Vector3
        """
        if isinstance(other, Vector3):
            return Vector3(self.x + other.x, self.y + other.y, self.z + other.z)
        raise TypeError("Unsupported type for addition with Vector3")
    
    def __sub__(self, other):
        """
        实现向量减法。
        
        :param other: 另一个 Vector3 对象
        :type other: Vector3
        :return: 新的 Vector3 对象，表示两个向量的差
        :rtype: Vector3
        """
        if isinstance(other, Vector3):
            return Vector3(self.x - other.x, self.y - other.y, self.z - other.z)
        raise TypeError("Unsupported type for subtraction with Vector3")
    
    def __mul__(self, scalar):
        """
        实现向量与标量的乘法。
        
        :param scalar: 一个数值，表示缩放因子
        :type scalar: float
        :return: 新的 Vector3 对象，表示向量缩放后的结果
        :rtype: Vector3
        """
        if isinstance(scalar, (int, float)):
            return Vector3(self.x * scalar, self.y * scalar, self.z * scalar)
        raise TypeError("Unsupported type for multiplication with Vector3")
    

    def __str__(self):
        """
        返回向量的字符串表示。
        
        :return: 形如 "(x,y,z)" 的字符串
        :rtype: str
        """
        return f"({self.x},{self.y},{self.z})"
    
    def to_str(self):
        """
        将向量转换为字符串格式。
        
        :return: 形如 "x,y,z" 的字符串
        :rtype: str
        """
        return f"{self.x},{self.y},{self.z}"

class Transform:
    """
    变换类，表示三维空间中的位置、旋转和缩放。

    :ivar location: 位置向量
    :vartype location: Vector3
    :ivar rotation: 旋转（欧拉角/四元数/Rotator）
    :vartype rotation: Rotator
    :ivar scale: 缩放向量
    :vartype scale: Vector3
    """

    def __init__(self, location: 'Vector3' = Vector3(0,0,0), rotation: 'Rotator' = Rotator(0,0,0), scale: 'Vector3' = Vector3(1,1,1)):
        self.location = location
        self.rotation = rotation
        self.scale = scale


    @staticmethod
    def from_str(s: str):
        """
        从字符串创建 Transform 对象。
        字符串格式: "x,y,z|pitch,yaw,roll|sx,sy,sz"
        例如: "1,2,3|0,90,0|1,1,1"
        """
        parts = s.split('|')
        if len(parts) != 3:
            raise ValueError("Transform string must have 3 parts separated by '|'")
        location = Vector3.from_str(parts[0])
        rotation = Rotator.from_str(parts[1])
        scale = Vector3.from_str(parts[2])
        return Transform(location, rotation, scale)

    def to_str(self) -> str:
        """
        转换为字符串格式: "x,y,z|pitch,yaw,roll|sx,sy,sz"
        """
        return f"{self.location.to_str()}|{self.rotation.to_str()}|{self.scale.to_str()}"

    def __str__(self) -> str:
        return f"({self.location.to_str()}|{self.rotation.to_str()}|{self.scale.to_str()})"

    

class LinearColor:
    """
    线性色彩类，表示 RGBA 颜色值。
    
    存储红、绿、蓝和透明度值，通常用于渲染和图形处理。
    
    :ivar r: 红色分量，范围通常为 0.0-1.0
    :vartype r: float
    :ivar g: 绿色分量，范围通常为 0.0-1.0
    :vartype g: float
    :ivar b: 蓝色分量，范围通常为 0.0-1.0
    :vartype b: float
    :ivar a: 透明度分量，范围通常为 0.0-1.0，其中 1.0 表示完全不透明
    :vartype a: float
    """
    
    @staticmethod
    def from_str(s):
        """
        从字符串创建 LinarColor 对象。
        
        :param s: 格式为 "r,g,b,a" 的字符串
        :type s: str
        :return: 新的 LinarColor 对象
        :rtype: LinarColor
        
        :example:
        
        >>> LinarColor.from_str("1.0,0.5,0.0,1.0")
        (1.0,0.5,0.0,1.0)
        """
        parts = s.split(",")
        r, g, b, a = map(float, parts[:4])
        return LinearColor(r, g, b, a)
    
    def __init__(self, r, g, b, a):
        """
        初始化 LinarColor 实例。
        
        :param r: 红色分量
        :type r: float
        :param g: 绿色分量
        :type g: float
        :param b: 蓝色分量
        :type b: float
        :param a: 透明度分量
        :type a: float
        """
        self.r = r
        self.g = g
        self.b = b
        self.a = a
    
    def __str__(self):
        """
        返回颜色的字符串表示。
        
        :return: 形如 "(r,g,b,a)" 的字符串
        :rtype: str
        """
        return f"({self.r},{self.g},{self.b},{self.a})"
    
    def to_str(self):
        """
        将颜色转换为字符串格式。
        
        :return: 形如 "r,g,b,a" 的字符串
        :rtype: str
        """
        return f"{self.r},{self.g},{self.b},{self.a}"

class D5ApiActorType(Enum):
    """
    D5 API 中的行为体（Actor）类型枚举。
    
    定义了 D5 系统中所有可用的行为体类型，用于对象分类和标识。
    """
    
    NoType = "NoType"
    """无类型"""
    
    Furniture = "Furniture"
    """常规模型，植物，导入的模型等"""
    
    PointLight = "PointLight"
    """点光源"""
    
    SpotLight = "SpotLight"
    """聚光灯"""
    
    AreaLight = "AreaLight"
    """区域光"""
    
    StageLight = "StageLight"
    """舞台灯光"""
    
    ProjectionLight = "ProjectionLight"
    """投影灯光"""
    
    BeltLight = "BeltLight"
    """带状灯光"""
    
    PlantSpline = "PlantSpline"
    """植物曲线"""
    
    CarSpline = "CarSpline"
    """车辆曲线"""
    
    PersonSpline = "PersonSpline"
    """人物曲线"""
    
    BPModel = "BPModel"
    """蓝图模型"""
    
    Niagara = "Niagara"
    """Niagara 粒子系统"""
    
    Decal = "Decal"
    """贴花"""
    
    SplinePoint = "SplinePoint"
    """样条点"""
    
    FusionGroup = "FusionGroup"
    """融合组"""
    
    CommonLight = "CommonLight"
    """通用灯光"""
    
    Clip = "Clip"
    """剪辑"""
    
    Camera = "Camera"
    """相机"""
    
    LiveSync = "LiveSync"
    """实时同步"""
    
    VideoView = "VideoView"
    """视频视图"""
    
    VideoShot = "VideoShot"
    """视频镜头"""
    
    VideoClip = "VideoClip"
    """视频剪辑"""
    
    Scatter = "Scatter"
    """散布"""
    
    GrowthAnimation = "GrowthAnimation"
    """生长动画"""
    
    Landscape = "Landscape"
    """地形"""
    
    LandscapeTemplate = "LandscapeTemplate"
    """地形模板"""
    
    City = "City"
    """城市"""

    @staticmethod
    def from_str(value: str) -> 'D5ApiActorType':
        """
        从字符串创建 D5ApiActorType 枚举值。
        
        :param value: 表示行为体类型的字符串
        :type value: str
        :return: 对应的 D5ApiActorType 枚举值
        :rtype: D5ApiActorType
        :raises ValueError: 如果提供的字符串不是有效的行为体类型
        
        :example:
        
        >>> D5ApiActorType.from_str("Camera")
        D5ApiActorType.Camera
        """
        return D5ApiActorType(value)
    
    def to_str(self) -> str:
        """
        将枚举值转换为字符串。
        
        :return: 表示行为体类型的字符串
        :rtype: str
        
        :example:
        
        >>> D5ApiActorType.Camera.to_str()
        'Camera'
        """
        return self.value
    
class LightType(Enum):
    """
    灯光类型枚举，定义了系统支持的不同类型灯光。
    
    用于灯光创建和管理过程中的类型标识。
    """
    
    POINT_LIGHT = "PointLight"
    """点光源，从一个点向所有方向均匀发射光线"""
    
    SPOT_LIGHT = "SpotLight"
    """聚光灯，从一个点向特定方向发射锥形光线"""
    
    AREA_LIGHT = "AreaLight"
    """区域光，从一个面积发射光线"""
    
    STAGE_LIGHT = "StageLight"
    """舞台灯光，特定用于舞台效果的灯光类型"""
    
    PROJECTION_LIGHT = "ProjectionLight"
    """投影灯光，可以投射图案或纹理的灯光"""
    
    BELT_LIGHT = "BeltLight"
    """带状灯光，沿线条或路径发射的灯光"""

class D5Scene:
    def __init__(self, scene_id, name, image_path, scenecamid):
        """
        初始化 Scene 实例。

        :param scene_id: 场景的唯一标识符
        :type scene_id: int or str
        :param name: 场景名称
        :type name: str
        :param image_path: 场景预览图像路径
        :type image_path: str
        :param scenecamid: 场景相机 ID
        :type scenecamid: int or str
        """
        self.scene_id = scene_id
        self.name = name
        self.image_path = image_path
        self.scene_ca_mid = scenecamid
    def __str__(self):
        """
        返回场景的字符串表示。
        
        :return: 形如 "Scene(scene_id, name, image_path, scene_cam_id)" 的字符串
        :rtype: str
        """
        return f"Scene({self.scene_id}, {self.name}, {self.image_path}, {self.scene_cam_id})"
